#include "_nodes_gen.h"
#include "BinaryTree.h"
#include "Array_Binary_Tree.h"
#include "Report_Table.h"
#include "TF_main.h"

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <windows.h>

/* Entry point for Test Framework
   Test Framework will,
 
   1) Run insertion for each entry in _nodes_gen with option given for which type to insert
   2) Profile total insertion time.
   3) _nodes_gen is randomized array of nodes.
 
   1) Run find for randomized entry in _nodes_gen with option given for which type to find
   2) Profile total find time.
   3) _find_nodes_gen contains randomized array to find.  
	 
	 Auguments: -i [normal|array] will do insertion
							-f [normal|array] will do find
*/

/*
static ReportTable *binary_tree_insertion_t      = new ReportTable("Binary_Tree_Insertion_Table");
static ReportTable *arr_binary_tree_insertion_t  = new ReportTable("Array_Binary_Tree_Insertion_Table");
static ReportTable *binary_tree_find_t           = new ReportTable("Binary_Tree_Find_Table");
static ReportTable *arr_binary_tree_find_t       = new ReportTable("Array_Binary_Tree_Find_Table");
*/

/******************************************
		LOCAL VARIABLES
 ******************************************/
TreeMode tree_mode = TREE_MODE_NONE;
TestMode test_mode = TEST_MODE_NONE;

/* For profiling. */
double PCFreq = 0.0;
__int64 CounterStart = 0;

/******************************************
		LOCAL FUNCTIONS
 ******************************************/
/* Reset and start profiling counter. */
void StartCounter()
{
    LARGE_INTEGER li;
    if(!QueryPerformanceFrequency(&li))
        printf("QueryPerformanceFrequency failed!\n");

	/* use microseconds */
    PCFreq = double(li.QuadPart)/1000000.0;

    QueryPerformanceCounter(&li);
    CounterStart = li.QuadPart;
}

/* Get profiling counter. */
double GetCounter()
{
    LARGE_INTEGER li;
    QueryPerformanceCounter(&li);
    return double(li.QuadPart-CounterStart)/PCFreq;
}

/********************************
	FUNCTION:processArgs
*********************************/
void processArgs
(
	int 	*argc_ptr, 
	char 	*argv[]
)
{
	/* First argument is the name of the program */
	*(argv++);
	(*argc_ptr)--;
	
	if( 0 == strcmp(*argv, "-i") )
	{
		*(argv++);
		(*argc_ptr)--;
		
		if( 0 == strcmp(*argv, "normal") )
		{
			tree_mode = TREE_MODE_NORMAL;
			test_mode = TEST_MODE_INSERTION;
		}
		else if( 0 == strcmp(*argv, "array") )
		{
			tree_mode = TREE_MODE_ARRAY;
			test_mode = TEST_MODE_INSERTION;
		}
		else
		{
			printf("Please use either normal or array for -i command!");
		}
	}
	else if( 0 == strcmp(*argv, "-f") )
	{
		*(argv++);
		(*argc_ptr)--;
		
		if( 0 == strcmp(*argv, "normal") )
		{
			tree_mode = TREE_MODE_NORMAL;
			test_mode = TEST_MODE_FIND;
		}
		else if( 0 == strcmp(*argv, "array") )
		{
			tree_mode = TREE_MODE_ARRAY;
			test_mode = TEST_MODE_FIND;
		}
		else
		{
			printf("Please use either normal or array for -i command!");
		}		
	}
	else
	{
		printf("Please use -h to see what command to type!");
	}
} /* processArgs */

/********************************
	FUNCTION:run_test
*********************************/
void run_test()
{
	if( TREE_MODE_NORMAL == tree_mode )
	{
		if( TEST_MODE_INSERTION == test_mode)
		{
			run_test_insertion_normal();
		}
		else if( TEST_MODE_FIND == test_mode )
		{
			run_test_find_normal();
		}
	}
	else if( TREE_MODE_ARRAY == tree_mode)
	{
		if( TEST_MODE_INSERTION == test_mode)
		{
			run_test_insertion_array();
		}
		else if( TEST_MODE_FIND == test_mode )
		{
			run_test_find_array();
		}
	}
} /* run_test */

/********************************
	FUNCTION:run_test_find_array
*********************************/
void run_test_find_array()
{
  a_init_binary_tree();
  for(uint i = 0; i < ARR_SIZE(_nodes_gen); i++ )
  {
    a_insert_element( _nodes_gen[i] );
  }

  /* Find the elements. */
  assert( ARR_SIZE(_find_array) <= ARR_SIZE(_nodes_gen) );
  for(uint i = 0; i < ARR_SIZE(_find_array); i++)
  {
    A_Node* elem = a_find_element( _find_array[i] );
    assert( elem != NULL );
  }
  printf( "Find array size: %d\n", ARR_SIZE(_find_array) );
} /* run_test_find_array */

/********************************
	FUNCTION:run_test_find_normal
*********************************/
void run_test_find_normal()
{
  init_binary_tree();
  /* Insert nodes to tree. */
  for(uint i = 0; i < ARR_SIZE(_nodes_gen); i++ )
  {
    insert_element( _nodes_gen[i] );
  }

  /* Find the elements. */
  assert( ARR_SIZE(_find_array) <= ARR_SIZE(_nodes_gen) );
  for(uint i = 0; i < ARR_SIZE(_find_array); i++)
  {
    Node* elem = find_element( _find_array[i] );
    assert( elem != NULL );
  }
  printf( "Find normal size: %d\n", size() );
} /* run_test_find_normal */

/********************************
	FUNCTION:run_test_insertion_array
*********************************/
void run_test_insertion_array()
{
  a_init_binary_tree();
  for(uint i = 0; i < ARR_SIZE(_nodes_gen); i++ )
  {
    a_insert_element( _nodes_gen[i] );
  }
  printf( "Insert array size: %d\n", a_size() );
} /* run_test_insertion_array */

/********************************
	FUNCTION:run_test_insertion_normal
*********************************/
void run_test_insertion_normal()
{
  init_binary_tree();
  for(uint i = 0; i < ARR_SIZE(_nodes_gen); i++ )
  {
    insert_element( _nodes_gen[i] );
  }
  printf( "Insert normal size: %d\n", size() );
} /* run_test_insertion_normal */


/******************************************
		MAIN
 ******************************************/
int main(int argc, char *argv[])
{
  double time = 0;

  /* Process arguments. */
	processArgs(&argc, argv);

  /* Start testing and record time. */
  StartCounter();
  run_test();
  time = GetCounter();

  printf( "Time is: %f us\n", time );
  return 0;
}


